﻿using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    class CustomFoldingStrategy : AbstractFoldingStrategy
    {
        private ICSharpCode.AvalonEdit.TextEditor edit;

        public ICSharpCode.AvalonEdit.TextEditor Edit { get { return this.edit; } }

        /// <summary>
        /// Creates a new BraceFoldingStrategy.
        /// </summary>
        public CustomFoldingStrategy(ICSharpCode.AvalonEdit.TextEditor edit)
        {
            this.edit = edit;
        }

        /// <summary>
        /// Create <see cref="NewFolding"/>s for the specified document.
        /// </summary>
        public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
        {
            firstErrorOffset = -1;
            return CreateNewFoldings(document);
        }

        /// <summary>
        /// Create <see cref="NewFolding"/>s for the specified document.
        /// </summary>
        public IEnumerable<NewFolding> CreateNewFoldings(ITextSource document)
        {
            List<NewFolding> newFoldings = new List<NewFolding>();

            List<Header> preHeaders = new List<Header>();

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);

                string text = edit.Document.GetText(line.Offset, line.Length);

                if (text.StartsWith("#") == false && CustomMarkdownSupport.IsTodoLine(text) == false) continue;

                var headerText = GetHeaderOfTitleOrTodolistItem(text);
                var contentText = GetContentOfTitleOrTodolistItem(text);

                var newHeader = new Header()
                {
                    HeaderText = headerText,
                    ContentText = contentText,
                    Length = headerText.Length,
                    Offset = line.Offset,
                    EndOffset = line.EndOffset,
                };

                if (preHeaders.Count <= 0)
                {
                    preHeaders.Add(newHeader);
                    continue;
                }

                for (int j = preHeaders.Count - 1; j >= 0; j--)
                {
                    if (newHeader.Length <= preHeaders[j].Length)
                    {
                        var endOffset = newHeader.Offset - 2;//-2是\r\n的宽度

                        //如果在这个标题只有一行，不折叠
                        if (endOffset > preHeaders[j].EndOffset)
                        {
                            var newFolding = new NewFolding(preHeaders[j].Offset, newHeader.Offset - 2)
                            {
                                Name = BuildTitleOrTodolistItemHeader(preHeaders[j].HeaderText) +
                                    (string.IsNullOrEmpty(preHeaders[j].ContentText) ?
                                    "... " :
                                    preHeaders[j].ContentText) + " ※ ",
                            };
                            newFoldings.Add(newFolding);
                        }
                        preHeaders.RemoveAt(j);
                    }
                }

                preHeaders.Add(newHeader);
            }

            //到最后一行，看看要不要添加折叠块。
            if (preHeaders.Count > 0)
            {
                var lastLine = this.edit.Document.GetLineByNumber(this.edit.Document.LineCount);
                if (lastLine != null)
                {
                    var lastLineText = this.edit.Document.GetText(lastLine);

                    if (lastLineText.StartsWith("#") == false && CustomMarkdownSupport.IsTodoLine(lastLineText) == false)
                    {

                        for (int j = preHeaders.Count - 1; j >= 0; j--)
                        {
                            var endOffset = edit.Document.Lines.Last().Offset;//最后一行，没有\r\n，不用 - 2;

                            //如果在这个标题只有一行，不折叠
                            if (endOffset > preHeaders[j].EndOffset)
                            {
                                newFoldings.Add(new NewFolding(preHeaders[j].Offset, endOffset)
                                {
                                    Name = BuildTitleOrTodolistItemHeader(preHeaders[j].HeaderText) +
                                        (string.IsNullOrEmpty(preHeaders[j].ContentText) ?
                                        "... " :
                                        preHeaders[j].ContentText + " ※ "),
                                });
                            }
                            preHeaders.RemoveAt(j);
                        }
                    }
                }
            }

            //添加试题所需要的折叠块
            Stack<int> startOffsets = new Stack<int>();
            string openingBrace = "试题＞＞";
            string closingBrace = "〓〓〓〓〓〓";

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);
                var preLine = line.PreviousLine;

                string text = edit.Document.GetText(line.Offset, line.Length).TrimStart();

                if (text.StartsWith(openingBrace))
                {
                    if (preLine != null && startOffsets.Count > 0)
                    {
                        int startOffset = startOffsets.Pop();
                        // don't fold if opening and closing brace are on the same line
                        if (startOffset < preLine.Offset)
                        {
                            newFoldings.Add(new NewFolding(startOffset, preLine.EndOffset)
                            {
                                Name = openingBrace,
                            });
                        }
                    }

                    startOffsets.Push(line.Offset);
                }
                else if (text.StartsWith(closingBrace) && startOffsets.Count > 0)
                {
                    int startOffset = startOffsets.Pop();
                    // don't fold if opening and closing brace are on the same line
                    if (startOffset < line.EndOffset)
                    {
                        newFoldings.Add(new NewFolding(startOffset, line.EndOffset)
                        {
                            Name = openingBrace,
                        });
                    }
                }
            }

            newFoldings.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset));
            return newFoldings;
        }

        private string BuildTitleOrTodolistItemHeader(string header)
        {
            if (string.IsNullOrWhiteSpace(header)) return "";

            if (header.StartsWith("[-]") || header.StartsWith("[－]")) return "[-] ";
            if (header.StartsWith("[+]")) return "[+] ";
            if (header.StartsWith("[%]")) return "[%] ";
            if (header.StartsWith("[#]")) return "[#] ";

            var level = header.Length;
            switch (level)
            {
                case 1: return "Ⅰ ※ ";
                case 2: return "Ⅱ ※ ";
                case 3: return "Ⅲ ※ ";
                case 4: return "Ⅳ ※ ";
                case 5: return "Ⅴ ※ ";
                case 6: return "Ⅵ ※ ";
                default: return "";
            }
        }

        public string GetContentOfTitleOrTodolistItem(string src)
        {
            if (string.IsNullOrEmpty(src)) return "";

            if (CustomMarkdownSupport.IsTodoLine(src)) return CustomMarkdownSupport.GetContentOfTodolistItem(src);

            if (src.StartsWith("#") == false) return "";

            if (src.StartsWith("######")) return src.Substring(6);
            if (src.StartsWith("#####")) return src.Substring(5);
            if (src.StartsWith("####")) return src.Substring(4);
            if (src.StartsWith("###")) return src.Substring(3);
            if (src.StartsWith("##")) return src.Substring(2);
            if (src.StartsWith("#")) return src.Substring(1);

            return "";
        }

        public string GetHeaderOfTitleOrTodolistItem(string src)
        {
            if (string.IsNullOrEmpty(src)) return "";
            if (CustomMarkdownSupport.IsTodoLine(src))
            {
                return CustomMarkdownSupport.GetHeaderOfTodolistItem(src);
            }
            if (src.StartsWith("#") == false) return "";

            if (src.StartsWith("######")) return "######";
            if (src.StartsWith("#####")) return "#####";
            if (src.StartsWith("####")) return "####";
            if (src.StartsWith("###")) return "###";
            if (src.StartsWith("##")) return "##";
            if (src.StartsWith("#")) return "#";

            return "";
        }
    }

    public class Header
    {
        private string headerText = "...";
        public string HeaderText
        {
            get { return this.headerText; }
            set { this.headerText = value; }
        }

        private string contentText = "#";
        public string ContentText
        {
            get { return contentText; }
            set { this.contentText = value; }
        }

        private int length = 1;
        public int Length
        {
            get { return this.length; }
            set { this.length = value; }
        }

        private int offset = -1;
        public int Offset
        {
            get { return this.offset; }
            set { this.offset = value; }
        }

        private int endOffset = -1;
        public int EndOffset
        {
            get { return this.endOffset; }
            set { this.endOffset = value; }
        }

    }
}
